package com.mindskip.xzs.configuration.spring.security;
//这段代码是在后端配置Spring Security的一些功能和过滤器
//1. validateHttpSession(true): 配置验证HTTP会话，确保用户会话有效。
//2. rememberMe(): 配置"记住我"功能，通过设置key和tokenValiditySeconds来实现记住用户登录状态的功能。
//3. csrf().disable(): 禁用CSRF防护，CSRF（Cross-Site Request Forgery）是一种网络攻击方式，这里禁用CSRF保护功能。
//4. cors(): 启用跨域资源共享（CORS），这段代码配置了CORS的相关参数，允许跨域请求。
//5. CorsConfigurationSource corsConfigurationSource(): 配置CORS的具体参数，设置允许的来源、方法、头部等信息。
//6. authenticationFilter(): 创建自定义认证过滤器，这里创建了一个RestLoginAuthenticationFilter，设置了认证成功和失败处理器，认证管理器和用户详细信息服务。
//配置Spring Security的一些功能和过滤器，包括会话验证、记住我功能、CSRF保护禁用、CORS配置和自定义认证过滤器的创建。这些功能和过滤器可以帮助实现安全的用户认证和授权机制。
import com.mindskip.xzs.configuration.property.CookieConfig;
import com.mindskip.xzs.configuration.property.SystemConfig;
import com.mindskip.xzs.domain.enums.RoleEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Collections;
import java.util.List;

/**
 * SecurityConfigurer 类定义了 Spring Security 配置。
 */
@Configuration
@EnableWebSecurity
public class SecurityConfigurer {

    /**
     * FormLoginWebSecurityConfigurerAdapter 内部静态类，用于配置基于表单登录的安全性。
     */
    @Configuration
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

        // 系统配置
        private final SystemConfig systemConfig;
        // 自定义认证入口点
        private final LoginAuthenticationEntryPoint restAuthenticationEntryPoint;
        // 自定义认证提供者
        private final RestAuthenticationProvider restAuthenticationProvider;
        // 用户详细信息服务
        private final RestDetailsServiceImpl formDetailsService;
        // 认证成功处理器
        private final RestAuthenticationSuccessHandler restAuthenticationSuccessHandler;
        // 认证失败处理器
        private final RestAuthenticationFailureHandler restAuthenticationFailureHandler;
        // 注销成功处理器
        private final RestLogoutSuccessHandler restLogoutSuccessHandler;
        // 访问被拒绝处理器
        private final RestAccessDeniedHandler restAccessDeniedHandler;

        /**
         * 构造函数，自动注入依赖。
         *
         * @param systemConfig 系统配置
         * @param restAuthenticationEntryPoint 自定义认证入口点
         * @param restAuthenticationProvider 自定义认证提供者
         * @param formDetailsService 用户详细信息服务
         * @param restAuthenticationSuccessHandler 认证成功处理器
         * @param restAuthenticationFailureHandler 认证失败处理器
         * @param restLogoutSuccessHandler 注销成功处理器
         * @param restAccessDeniedHandler 访问被拒绝处理器
         */
        @Autowired
        public FormLoginWebSecurityConfigurerAdapter(SystemConfig systemConfig, LoginAuthenticationEntryPoint restAuthenticationEntryPoint, RestAuthenticationProvider restAuthenticationProvider, RestDetailsServiceImpl formDetailsService, RestAuthenticationSuccessHandler restAuthenticationSuccessHandler, RestAuthenticationFailureHandler restAuthenticationFailureHandler, RestLogoutSuccessHandler restLogoutSuccessHandler, RestAccessDeniedHandler restAccessDeniedHandler) {
            this.systemConfig = systemConfig;
            this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
            this.restAuthenticationProvider = restAuthenticationProvider;
            this.formDetailsService = formDetailsService;
            this.restAuthenticationSuccessHandler = restAuthenticationSuccessHandler;
            this.restAuthenticationFailureHandler = restAuthenticationFailureHandler;
            this.restLogoutSuccessHandler = restLogoutSuccessHandler;
            this.restAccessDeniedHandler = restAccessDeniedHandler;
        }

        /**
         * 配置 HTTP 安全性。
         *
         * @param http HttpSecurity 对象
         * @throws Exception 如果配置失败
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 禁用 frameOptions
            http.headers().frameOptions().disable();

            // 从系统配置中获取忽略安全性的 URL 列表
            List<String> securityIgnoreUrls = systemConfig.getSecurityIgnoreUrls();
            String[] ignores = new String[securityIgnoreUrls.size()];

            // 配置 HTTP 安全性
            http
                    // 添加自定义认证过滤器
                    .addFilterAt(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                    // 配置异常处理
                    .exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint)
                    .and().authenticationProvider(restAuthenticationProvider)
                    // 配置授权请求
                    .authorizeRequests()
                    // 忽略安全性的 URL
                    .antMatchers(securityIgnoreUrls.toArray(ignores)).permitAll()
                    // 只有 ADMIN 角色可以访问的 URL
                    .antMatchers("/api/admin/**").hasRole(RoleEnum.ADMIN.getName())
                    // 只有 STUDENT 角色可以访问的 URL
                    .antMatchers("/api/student/**").hasRole(RoleEnum.STUDENT.getName())
                    // 其他所有请求允许访问
                    .anyRequest().permitAll()
                    .and().exceptionHandling().accessDeniedHandler(restAccessDeniedHandler)
                    // 配置表单登录
                    .and().formLogin().successHandler(restAuthenticationSuccessHandler).failureHandler(restAuthenticationFailureHandler)
                    // 配置注销
                    .and().logout().logoutUrl("/api/user/logout").logoutSuccessHandler(restLogoutSuccessHandler).invalidateHttpSession(true)
                    // 配置 "记住我" 功能
                    .and().rememberMe().key(CookieConfig.getName()).tokenValiditySeconds(CookieConfig.getInterval()).userDetailsService(formDetailsService)
                    // 禁用 CSRF
                    .and().csrf().disable()
                    // 启用 CORS
                    .cors();
        }

        /**
         * 配置 CORS。
         *
         * @return CorsConfigurationSource 对象
         */
        @Bean
        public CorsConfigurationSource corsConfigurationSource() {
            final CorsConfiguration configuration = new CorsConfiguration();
            // 设置 CORS 配置
            configuration.setMaxAge(3600L);
            configuration.setAllowedOrigins(Collections.singletonList("*"));
            configuration.setAllowedMethods(Collections.singletonList("*"));
            configuration.setAllowCredentials(true);
            configuration.setAllowedHeaders(Collections.singletonList("*"));
            final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/api/**", configuration);
            return source;
        }

        /**
         * 创建自定义认证过滤器。
         *
         * @return RestLoginAuthenticationFilter 对象
         * @throws Exception 如果创建失败
         */
        @Bean
        public RestLoginAuthenticationFilter authenticationFilter() throws Exception {
            RestLoginAuthenticationFilter authenticationFilter = new RestLoginAuthenticationFilter();
            // 设置认证成功和失败处理器
            authenticationFilter.setAuthenticationSuccessHandler(restAuthenticationSuccessHandler);
            authenticationFilter.setAuthenticationFailureHandler(restAuthenticationFailureHandler);
            // 设置认证管理器
            authenticationFilter.setAuthenticationManager(authenticationManagerBean());
            // 设置用户详细信息服务
            authenticationFilter.setUserDetailsService(formDetailsService);
            return authenticationFilter;
        }
    }
}
